#include <iostream>     // 包含输入输出流库
#include <cstdio>       // 包含标准输入输出库
#include <string>       // 包含C++字符串库
#include <cstring>      // 包含C字符串处理库
#include <cstdlib>      // 包含C标准库
#include <unistd.h>     // 包含POSIX操作系统API
#include <sys/types.h>  // 包含数据类型定义
#include <sys/wait.h>   // 包含进程等待函数

#define N 2             // 定义常量N为2
#define NUM 1024        // 定义常量NUM为1024，表示缓冲区大小

using namespace std;    // 使用标准命名空间

// Writer函数，向管道写数据
void Writer(int wfd)
{
    string s = "i am father";    // 定义字符串s
    pid_t self = getpid();       // 获取当前进程ID
    int number = 0;              // 定义一个计数器number，初始值为0

    char buffer[NUM];            // 定义缓冲区buffer
    while (true)                 // 无限循环
    {
        sleep(1);                // 休眠1秒

        buffer[0] = 0;           // 将缓冲区第一个位置置为0
        snprintf(buffer, sizeof(buffer), "%s-%d-%d", s.c_str(), self, number++); // 格式化字符串并存入缓冲区
        cout << buffer << endl;  // 输出缓冲区内容

        write(wfd, buffer, strlen(buffer)); // 将缓冲区内容写入管道

        if(number>=5)            // 如果计数器number大于等于5，退出循环
            break;
    }
}

// Reader函数，从管道读数据
void Reader(int rfd)
{
    char buffer[NUM];            // 定义缓冲区buffer

    int _count =0;

    while(true)                  // 无限循环
    {
        buffer[0] = 0;           // 将缓冲区第一个位置置为0
        ssize_t n = read(rfd, buffer, sizeof(buffer)); // 从管道读取数据存入缓冲区
        if(n > 0)                // 如果读取到的数据长度大于0
        {
            buffer[n] = 0;       // 将缓冲区第n个位置置为0，表示字符串结束
            cout << "child get a message[" << getpid() << "]# " << buffer << endl; // 输出读取到的内容
        }
        else if(n == 0)          // 如果读取到的数据长度为0，表示管道已关闭
        {
            printf("child read file done!\n"); // 输出读取完成信息
            break;               // 退出循环
        }
        else break;              // 如果读取错误，退出循环

        _count++;
        if(_count>=2)
            break;
    }
}

int main()
{
    int pipefd[N] = {0};         // 定义一个数组pipefd，用于存放管道的文件描述符
    int n = pipe(pipefd);        // 创建管道，返回值n小于0表示创建失败
    if (n < 0)
        return 1;                // 如果创建管道失败，返回1

    pid_t id = fork();           // 创建子进程，返回值id小于0表示创建失败
    if (id < 0)
        return 2;                // 如果创建子进程失败，返回2

    if (id == 0)
    {
        // 子进程代码
        close(pipefd[1]);        // 关闭管道的写端

        // IPC代码
        Reader(pipefd[0]);       // 调用Reader函数，从管道读取数据

        close(pipefd[0]);        // 关闭管道的读端
        exit(0);                 // 退出子进程
    }
    // 父进程代码
    close(pipefd[0]);            // 关闭管道的读端
    // IPC代码
    Writer(pipefd[1]);           // 调用Writer函数，向管道写入数据
    close(pipefd[1]);            // 关闭管道的写端

    pid_t rid = waitpid(id, nullptr, 0); // 等待子进程结束
    if(rid < 0) return 3;        // 如果等待失败，返回3

    sleep(5);                    // 休眠5秒
    return 0;                    // 返回0，表示程序成功结束
}
